package future;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import util.Util;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author yding5
 */
public class CompletableFutureTest {

    private static ExecutorService EXECUTOR_SERVICE;

    @Before
    public void setup() {
        EXECUTOR_SERVICE = Executors.newCachedThreadPool();
    }

    @After
    public void cleanup() {
        EXECUTOR_SERVICE.shutdownNow();
    }

    @Test
    public void test() {
        Util.timeWatch();
        CompletableFuture<String> taskA =
                CompletableFuture.supplyAsync(() -> finishTaskA(), EXECUTOR_SERVICE)
                        .orTimeout(1, TimeUnit.SECONDS)
                        .exceptionally(e -> null);
        CompletableFuture<String> taskC =
                taskA.thenApply((a) -> finishTaskC(a))
                        .orTimeout(1, TimeUnit.SECONDS)
                        .exceptionally(e -> null);
        CompletableFuture<String> taskB =
                CompletableFuture.supplyAsync(() -> finishTaskB(), EXECUTOR_SERVICE)
                        .orTimeout(1, TimeUnit.SECONDS)
                        .exceptionally(e -> null);
        CompletableFuture<Void> end = CompletableFuture.allOf(taskC, taskB);
        end.join();
        Util.timeWatch();
    }

    private static String finishTaskA() {
        Util.sleep(100L);
        Util.print("finish task A.");
        return "A";
    }

    private static String finishTaskB() {
        Util.sleep(200L);
        Util.print("finish task B.");
        return "B";
    }

    private static String finishTaskC(String A) {
        Util.sleep(300L);
        Util.print("finish task C based on " + A);
        return "C";
    }
}
